using System;
using SMS.SMPPClient.Util;
using SMS.SMPPClient.PDU;

namespace SMS.SMPPClient.PDU.Incoming
{
    /// <summary>
    /// This class defines a deliver_sm that is SMSC generated.  This does
    /// NOT handle anything other than strings in the short message.
    /// </summary>
    public class SMPPDeliverSM : SMPPResponse
    {
        private string _ServiceType;
        private byte _SourceAddrTON;
        private byte _SourceAddrNPI;
        private string _SourceAddress;
        private byte _DestAddrTON;
        private byte _DestAddrNPI;
        private string _DestAddress;
        private byte _ESMClass;
        private byte _ProtocolID;
        private byte _PriorityFlag;
        private byte _RegisteredDelivery;
        private byte _DataCoding;
        private byte _SMLength;
        private string _ShortMessage;


        /// <summary>
        /// Used to indicate the SMS Application service associated with the message.
        /// If this is unknown, null is returned.
        /// </summary>
        public string ServiceType
        {
            get
            {
                if (_ServiceType == null || _ServiceType.Length <= 1)
                {
                    return null;
                }
                return _ServiceType;
            }
        }

        /// <summary>
        /// Type of Number for source address.
        /// </summary>
        public TONType SourceAddrTON
        {
            get
            {
                return (TONType)Enum.Parse(typeof(TONType),
                                                 Enum.GetName(typeof(TONType), _SourceAddrTON));
            }
        }

        /// <summary>
        /// Numbering Plan Indicator for source address.
        /// </summary>
        public NPIType SourceAddrNPI
        {
            get
            {
                return (NPIType)Enum.Parse(typeof(NPIType),
                                                 Enum.GetName(typeof(NPIType), _SourceAddrNPI));
            }
        }

        /// <summary>
        /// Address of origination entity.
        /// </summary>
        public string SourceAddress
        {
            get
            {
                return _SourceAddress;
            }
        }

        /// <summary>
        /// Type of number of destination entity.
        /// </summary>
        public TONType DestAddrTON
        {
            get
            {
                return (TONType)Enum.Parse(typeof(TONType),
                                                 Enum.GetName(typeof(TONType), _DestAddrTON));
            }
        }

        /// <summary>
        /// Numbering Plan Indicator of destination entity.
        /// </summary>
        public NPIType DestAddrNPI
        {
            get
            {
                return (NPIType)Enum.Parse(typeof(NPIType),
                                                 Enum.GetName(typeof(NPIType), _DestAddrNPI));
            }
        }

        /// <summary>
        /// Destination address of entity.
        /// </summary>
        public string DestAddress
        {
            get
            {
                return _DestAddress;
            }
        }

        /// <summary>
        /// Indicates Message Mode and Message Type.  See the SMSC
        /// version 3.4 specification for details on this.
        /// </summary>
        public byte ESMClass
        {
            get
            {
                return _ESMClass;
            }
        }

        /// <summary>
        /// Protocol Identifier; network specific.
        /// </summary>
        public byte ProtocolID
        {
            get
            {
                return _ProtocolID;
            }
        }

        /// <summary>
        /// Designates the priority level of the message.
        /// </summary>
        public PriorityType PriorityFlag
        {
            get
            {
                return (PriorityType)Enum.Parse(typeof(PriorityType),
                                                    Enum.GetName(typeof(PriorityType), _PriorityFlag));
            }
        }

        /// <summary>
        /// This field is unused for deliver_sm.  It is always null.
        /// </summary>
        public string ScheduleDeliveryTime
        {
            get
            {
                return null;
            }
        }

        /// <summary>
        /// This field is unused for deliver_sm.  It is always null.
        /// </summary>
        public string ValidityPeriod
        {
            get
            {
                return null;
            }
        }

        /// <summary>
        /// Use this to indicate if you want delivery confirmation.
        /// </summary>
        public RegisteredDeliveryType RegisteredDelivery
        {
            get
            {
                return (RegisteredDeliveryType)Enum.Parse(typeof(RegisteredDeliveryType),
                        Enum.GetName(typeof(RegisteredDeliveryType), _RegisteredDelivery));
            }
        }

        /// <summary>
        /// This field is unused for deliver_sm.  It is always false.
        /// </summary>
        public bool ReplaceIfPresentFlag
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Indicates the encoding scheme of the short message.
        /// </summary>
        public DataCodingType DataCoding
        {
            get
            {
                return (DataCodingType)Enum.Parse(typeof(DataCodingType),
                                                        Enum.GetName(typeof(DataCodingType), _DataCoding));
            }
        }

        /// <summary>
        /// This field is unused for deliver_sm.  It is always null (i.e. 0x00).
        /// </summary>
        public byte SMDefaultMsgID
        {
            get
            {
                return 0x00;
            }
        }

        /// <summary>
        /// Short message length in octets (bytes for x86).
        /// </summary>
        public byte SMLength
        {
            get
            {
                return _SMLength;
            }
        }

        /// <summary>
        /// The short message for this PDU.  This holds up to 160 characters.
        /// If the message is longer, the MessagePayload property will be used.
        /// If this is the case, the short message length will be zero.  Note
        /// that both the ShortMessage and MessagePayload cannot be used
        /// simultaneously.
        /// </summary>
        public string ShortMessage
        {
            get
            {
                return _ShortMessage;
            }
        }

        //----------- start of optional parameters ----------------------------------

        /// <summary>
        /// The message reference number assigned by the ESME.
        /// </summary>
        public UInt16 UserMessageReference
        {
            get
            {
                return UnsignedNumConverter.SwapByteOrdering(
                             BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes((ushort)
                                                    OptionalParamCodes.user_message_reference), 0));
            }
        }

        /// <summary>
        /// The port number associated with the source address of the message.  This
        /// parameter will be present for WAP applications.
        /// </summary>
        public UInt16 SourcePort
        {
            get
            {
                return ConvertTLVNetworkBytesToUInt16((ushort)
                                                         OptionalParamCodes.source_port);
            }
        }

        /// <summary>
        /// The port number associated with the destination address of the message.  This
        /// parameter will be present for WAP applications.
        /// </summary>
        public UInt16 DestinationPort
        {
            get
            {
                return ConvertTLVNetworkBytesToUInt16((ushort)
                                                         OptionalParamCodes.destination_port);
            }
        }

        /// <summary>
        /// The reference number for a particular concatenated short message.
        /// </summary>
        public UInt16 SarMsgRefNumber
        {
            get
            {
                return ConvertTLVNetworkBytesToUInt16((ushort)
                                                         OptionalParamCodes.sar_msg_ref_num);
            }
        }

        /// <summary>
        /// Total number of short message fragments within the concatenated short message.
        /// </summary>
        public byte SarTotalSegments
        {
            get
            {
                return tlvTable.GetOptionalParamBytes((ushort)
                                                         OptionalParamCodes.sar_total_segments)[0];
            }
        }

        /// <summary>
        /// The sequence number of a particular short message fragment within the concatenated short message.
        /// </summary>
        public byte SarSegmentSeqnum
        {
            get
            {
                return tlvTable.GetOptionalParamBytes((ushort)
                                                         OptionalParamCodes.sar_segment_seqnum)[0];
            }
        }

        /// <summary>
        /// A user response code. The actual response codes are SMS application specific.
        /// </summary>
        public byte UserResponseCode
        {
            get
            {
                return tlvTable.GetOptionalParamBytes((ushort)
                                                         OptionalParamCodes.user_response_code)[0];
            }
        }

        /// <summary>
        /// Indicates a level of privacy associated with the message.
        /// </summary>
        public PrivacyType PrivacyIndicator
        {
            get
            {
                return (PrivacyType)Enum.Parse(typeof(PrivacyType),
                                                     Enum.GetName(typeof(PrivacyType),
                                                                 tlvTable.GetOptionalParamBytes((ushort)
                                                                                                 OptionalParamCodes.privacy_indicator)[0]));
            }
        }

        /// <summary>
        /// Defines the type of payload (e.g. WDP, WCMP, etc.)
        /// </summary>
        public PayloadTypeType PayloadType
        {
            get
            {
                return (PayloadTypeType)Enum.Parse(typeof(PayloadTypeType),
                                                         Enum.GetName(typeof(PayloadTypeType),
                                                                     tlvTable.GetOptionalParamBytes((ushort)
                                                                                                     OptionalParamCodes.payload_type)[0]));
            }
        }

        /// <summary>
        /// This can hold up to 64K octets of short message data.
        /// The actual limit is network/SMSC dependent.
        /// </summary>
        public string MessagePaylod
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.message_payload);
            }
        }

        /// <summary>
        /// Associates a callback number with a message.  See section 5.3.2.36 of the
        /// SMPP spec for details.  This must be between 4 and 19 characters in length.
        /// </summary>
        public string CallbackNum
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.callback_num);
            }
        }

        /// <summary>
        /// Specifies a source subaddress associated with the originating entity.
        /// See section 5.3.2.15 of the SMPP spec for details on setting this parameter.
        /// </summary>
        public string SourceSubaddress
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.source_subaddress);
            }
        }

        /// <summary>
        /// Specifies a source subaddress associated with the receiving entity.
        /// See section 5.3.2.15 of the SMPP spec for details on setting this parameter.
        /// </summary>
        public string DestinationSubaddress
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.dest_subaddress);
            }
        }

        /// <summary>
        /// The language of the short message.
        /// </summary>
        public LanguageType LanguageIndicator
        {
            get
            {
                return (LanguageType)Enum.Parse(typeof(LanguageType),
                                                    Enum.GetName(typeof(LanguageType),
                                                                    tlvTable.GetOptionalParamBytes((ushort)
                                                                                                    OptionalParamCodes.language_indicator)[0]));
            }
        }

        /// <summary>
        /// From the SMPP spec:
        /// The its_session_info parameter is a required parameter for the CDMA Interactive
        /// Teleservice as defined by the Korean PCS carriers [KORITS]. It contains control
        /// information for the interactive session between an MS and an ESME.
        ///
        /// See section 5.3.2.43 of the SMPP spec for how to set this.
        /// </summary>
        public string ITSSessionInfo
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.its_session_info);
            }
        }

        /// <summary>
        /// Network Error Code.  May be present for Intermediate Notifications
        /// and SMSC Delivery Receipts.  See SMPP spec 5.3.2.31 for details.
        /// </summary>
        public string NetworkErrorCode
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.network_error_code);
            }
        }

        /// <summary>
        /// Indicates to the ESME the final message state for an SMSC Delivery Receipt.
        /// </summary>
        public DPFResultType MessageState
        {
            get
            {
                return (DPFResultType)Enum.Parse(typeof(DPFResultType),
                                                     Enum.GetName(typeof(DPFResultType),
                                                                     tlvTable.GetOptionalParamBytes((ushort)
                                                                                                     OptionalParamCodes.message_state)[0]));
            }
        }

        /// <summary>
        /// Indicates the ID of the message being receipted in an SMSC Delivery Receipt.
        /// </summary>
        public string ReceiptedMessageID
        {
            get
            {
                return tlvTable.GetOptionalParamString((ushort)
                                                        OptionalParamCodes.receipted_message_id);
            }
        }

        //----------- end of optional parameters ------------------------------------


        /// <summary>
        /// Creates a deliver_sm PDU.
        /// </summary>
        public SMPPDeliverSM(byte[] response)
            : base(response)
        {
            DecodeSMSCResponse();
        }

        /// <summary>
        /// Retrieves the given bytes from the TLV table and converts them into a
        /// host order UInt16.
        /// </summary>
        /// <param name="tag">The TLV tag to use for retrieval</param>
        /// <returns>The host order result.</returns>
        private UInt16 ConvertTLVNetworkBytesToUInt16(ushort tag)
        {
            return UnsignedNumConverter.SwapByteOrdering(
                         BitConverter.ToUInt16(tlvTable.GetOptionalParamBytes(tag), 0));
        }

        /// <summary>
        /// This decodes the deliver_sm PDU.  The PDU has basically the same format as
        /// the submit_sm PDU, but in this case it is a response.
        /// </summary>
        protected override void DecodeSMSCResponse()
        {
            byte[] remainder = ResponseAfterHeader;
            _ServiceType = GetStringFromBody(ref remainder);
            _SourceAddrTON = remainder[0];
            _SourceAddrNPI = remainder[1];
            _SourceAddress = GetStringFromBody(ref remainder, 2);
            _DestAddrTON = remainder[0];
            _DestAddrNPI = remainder[1];
            _DestAddress = GetStringFromBody(ref remainder, 2);
            _ESMClass = remainder[0];
            _ProtocolID = remainder[1];
            _PriorityFlag = remainder[2];

            //schedule_delivery_time and validity_period are null, so don't bother
            //reading them

            _RegisteredDelivery = remainder[5];

            //replace_if_present is always null, so don't bother reading it

            _DataCoding = remainder[7];

            //sm_default_msg_id is always null, so don't bother reading it

            _SMLength = remainder[9];

            _ShortMessage = GetStringFromBody(ref remainder, 10, 10 + _SMLength);
            tlvTable.TranslateTLVDataIntoTable(remainder);
        }
    }
}
